package de.karlNet.sambamanager.ldapController.commands.macros;

import java.util.ArrayList;

import javax.naming.NamingException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Controller;

import de.karlNet.sambamanager.ldapController.LdapMemberOfTree;
import de.karlNet.sambamanager.ldapController.LdapMemberTree;
import de.karlNet.sambamanager.ldapController.commands.AddGroupMembersAndMemberOf;
import de.karlNet.sambamanager.ldapController.commands.BaseCommand;
import de.karlNet.sambamanager.ldapController.commands.ModifyGroup;
import de.karlNet.sambamanager.ldapController.commands.RemoveGroupFromGroup;
import de.karlNet.sambamanager.ldapController.commands.RemoveUserFromGroup;
import de.karlNet.sambamanager.ldapModel.ITypeCheckerCallback;
import de.karlNet.sambamanager.ldapModel.LdapGroup;
import de.karlNet.sambamanager.ldapModel.LdapObject;
import de.karlNet.sambamanager.ldapModel.LdapUser;
import de.karlNet.sambamanager.ldapModel.dto.LdapGroupModifyDTO;

@Controller
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ModifyGroupMacro extends BaseCommand {
	@Autowired
	private AddGroupMembersAndMemberOf addGroupMemberOf;
	@Autowired
	private ModifyGroup modifyGroup;
	@Autowired
	private LdapMemberOfTree memberOfTree;
	@Autowired
	private LdapMemberTree ldapMemberTree;
	@Autowired
	private RemoveGroupFromGroup removeGroupFromGroup;
	@Autowired
	private RemoveUserFromGroup removeUserFromGroup;

	public void modifyGroup(final LdapGroupModifyDTO ldapGroupCreationDTO)
			throws NamingException {
		final ArrayList<LdapObject> toRemoveMemberOf = new ArrayList<LdapObject>();
		for (final LdapObject ldapGroup : this.memberOfTree
				.getChildrenOfDN(ldapGroupCreationDTO.getOldGroup().getDn())) {
			ldapGroup.isType(new ITypeCheckerCallback() {
				@Override
				public void isGroup() {
					toRemoveMemberOf.add(ldapGroup);
				}
			});
		}
		toRemoveMemberOf.removeAll(ldapGroupCreationDTO.getMemberOf());
		ldapGroupCreationDTO.getMemberOf().removeAll(
				this.memberOfTree.getChildrenOfDN(ldapGroupCreationDTO
						.getLdapGroup().getDn()));
		for (final LdapObject ldapGroup : toRemoveMemberOf) {
			ldapGroup.isType(new ITypeCheckerCallback() {
				@Override
				public void isGroup(LdapGroup group) {
					removeGroupFromGroup.removeGroupFromGroup(group,
							ldapGroupCreationDTO.getLdapGroup());
				}
			});
		}

		final ArrayList<LdapObject> toRemoveMember = new ArrayList<LdapObject>();
		for (final LdapObject ldapGroup : this.ldapMemberTree
				.getChildrenOfDN(ldapGroupCreationDTO.getLdapGroup().getDn())) {
			ldapGroup.isType(new ITypeCheckerCallback() {
				@Override
				public void isGroup(LdapGroup group) {
					toRemoveMember.add(group);
				}
				
				@Override
				public void isUser(LdapUser ldapUser) {
					toRemoveMember.add(ldapUser);
				}
			});
		}
		toRemoveMember.removeAll(ldapGroupCreationDTO.getMembers());
		ldapGroupCreationDTO.getMembers().removeAll( this.ldapMemberTree
				.getChildrenOfDN(ldapGroupCreationDTO.getLdapGroup().getDn()));
		for (final LdapObject ldapGroup : toRemoveMember) {
			ldapGroup.isType(new ITypeCheckerCallback() {
				@Override
				public void isUser(LdapUser ldapUser) {
					removeUserFromGroup.removeUserFromGroupItself(
							ldapGroupCreationDTO.getLdapGroup(), ldapUser);
				}
				@Override
				public void isGroup(LdapGroup group) {
					removeGroupFromGroup.removeGroupFromGroup(
							ldapGroupCreationDTO.getLdapGroup(), group);
				}
			});
		}

		this.addGroupMemberOf.addUserToGroupItself(ldapGroupCreationDTO);
		this.modifyGroup.modifyGroupItself(ldapGroupCreationDTO);
		this.resetTrees();
	}
}
